package core

import (
	"github.com/hashicorp/go-hclog"
	"sync"
)

// ACS implements Asynchronous Common Subset protocol
type ACS struct {
	node   *Node
	logger hclog.Logger
	
	// Protocol instances
	rbc  *RBC
	aba  *ABA
	mvba *MVBA
	
	// ACS state
	activeSNs    map[int]bool // [SN]bool - active sequence numbers
	inputs       map[int][]byte // [SN]Input - input data for each SN
	outputs      map[int][]byte // [SN]Output - output data for each SN
	decisions    map[int]int    // [SN]Decision - ABA decisions
	completed    map[int]bool   // [SN]bool - completed sequence numbers
	
	// ACS parameters
	kappa int // number of parallel instances
	
	mutex sync.RWMutex
}

// NewACS creates a new ACS instance
func NewACS(node *Node) *ACS {
	return &ACS{
		node:      node,
		logger:    hclog.New(&hclog.LoggerOptions{Name: "dumbo-acs", Level: hclog.Level(node.Config.LogLevel)}),
		activeSNs: make(map[int]bool),
		inputs:    make(map[int][]byte),
		outputs:   make(map[int][]byte),
		decisions: make(map[int]int),
		completed: make(map[int]bool),
		kappa:     3, // Default kappa value
	}
}

// Initialize initializes the ACS with RBC, ABA, and MVBA instances
func (a *ACS) Initialize(rbc *RBC, aba *ABA, mvba *MVBA) {
	a.rbc = rbc
	a.aba = aba
	a.mvba = mvba
}

// StartACS starts the ACS protocol with given inputs
func (a *ACS) StartACS(inputs [][]byte) {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	
	a.logger.Info("ACS starting", "input_count", len(inputs))
	
	// 开始ACS延迟计时
	a.node.delayMonitor.StartACS(0) // 使用0作为ACS的SN
	
	// Start kappa parallel instances
	for i := 0; i < a.kappa && i < len(inputs); i++ {
		sn := i
		a.activeSNs[sn] = true
		a.inputs[sn] = inputs[i]
		
		// Start RBC for this SN
		go a.rbc.Broadcast(sn, inputs[i])
		
		a.logger.Debug("ACS started instance", "sn", sn, "input_len", len(inputs[i]))
	}
}

// ProcessRBCOutput processes RBC output and starts ABA
func (a *ACS) ProcessRBCOutput(sn int, data []byte) {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	
	if !a.activeSNs[sn] || a.completed[sn] {
		return
	}
	
	// Store RBC output
	a.outputs[sn] = data
	
	a.logger.Debug("ACS received RBC output", "sn", sn, "data_len", len(data))
	
	// Start ABA with input 1 (indicating we received the data)
	go a.aba.Start(sn, 1)
}

// ProcessABADecision processes ABA decision and starts MVBA
func (a *ACS) ProcessABADecision(sn int, decision int) {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	
	if !a.activeSNs[sn] || a.completed[sn] {
		return
	}
	
	// Store ABA decision
	a.decisions[sn] = decision
	
	a.logger.Debug("ACS received ABA decision", "sn", sn, "decision", decision)
	
	// If decision is 1, start MVBA with the RBC output
	if decision == 1 {
		if data, exists := a.outputs[sn]; exists {
			go a.mvba.Start(sn, data)
		}
	} else {
		// If decision is 0, mark as completed with empty output
		a.completed[sn] = true
		a.logger.Debug("ACS completed with decision 0", "sn", sn)
	}
}

// ProcessMVBAOutput processes MVBA output and completes ACS
func (a *ACS) ProcessMVBAOutput(sn int, data []byte) {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	
	if !a.activeSNs[sn] || a.completed[sn] {
		return
	}
	
	// Mark as completed
	a.completed[sn] = true
	
	// 结束ACS延迟计时并记录
	delay := a.node.delayMonitor.EndACS(0) // 使用0作为ACS的SN
	a.logger.Info("ACS completed", "sn", sn, "data_len", len(data), "delay_ms", delay.Milliseconds())
	
	// Check if all instances are completed
	if a.isAllCompleted() {
		a.logger.Info("ACS all instances completed")
		// Notify the node that ACS is complete
		go a.node.OnACSComplete(a.getCompletedOutputs())
	}
}

// isAllCompleted checks if all active instances are completed
func (a *ACS) isAllCompleted() bool {
	for sn := range a.activeSNs {
		if !a.completed[sn] {
			return false
		}
	}
	return true
}

// getCompletedOutputs returns all completed outputs
func (a *ACS) getCompletedOutputs() [][]byte {
	var outputs [][]byte
	for sn := range a.activeSNs {
		if a.completed[sn] {
			if data, exists := a.outputs[sn]; exists {
				outputs = append(outputs, data)
			}
		}
	}
	return outputs
}

// GetStatus returns the current status of ACS
func (a *ACS) GetStatus() map[string]interface{} {
	a.mutex.RLock()
	defer a.mutex.RUnlock()
	
	status := map[string]interface{}{
		"active_count":   len(a.activeSNs),
		"completed_count": len(a.completed),
		"active_sns":     make([]int, 0),
		"completed_sns":  make([]int, 0),
	}
	
	for sn := range a.activeSNs {
		status["active_sns"] = append(status["active_sns"].([]int), sn)
	}
	
	for sn := range a.completed {
		status["completed_sns"] = append(status["completed_sns"].([]int), sn)
	}
	
	return status
}

// IsCompleted checks if ACS is completed
func (a *ACS) IsCompleted() bool {
	a.mutex.RLock()
	defer a.mutex.RUnlock()
	
	return a.isAllCompleted()
}

// GetOutputs returns all outputs
func (a *ACS) GetOutputs() map[int][]byte {
	a.mutex.RLock()
	defer a.mutex.RUnlock()
	
	outputs := make(map[int][]byte)
	for sn, data := range a.outputs {
		outputs[sn] = data
	}
	return outputs
}
